package durst.data.dao.impl;

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;

import com.j256.ormlite.dao.BaseDaoImpl;
import com.j256.ormlite.dao.GenericRawResults;
import com.j256.ormlite.field.DataType;
import com.j256.ormlite.stmt.PreparedDelete;
import com.j256.ormlite.support.ConnectionSource;
import com.j256.ormlite.table.DatabaseTableConfig;

import durst.data.Account;
import durst.data.Friend;
import durst.data.dao.DaoFactory;

public class FriendDao<T, ID> extends BaseDaoImpl<T, ID> {
	@SuppressWarnings("unchecked")
	public FriendDao(ConnectionSource connectionSource) throws SQLException {
		super(connectionSource, (Class<T>) Friend.class);
	}

	public FriendDao(ConnectionSource connectionSource, DatabaseTableConfig<T> tableConfig)
			throws SQLException {
		super(connectionSource, tableConfig);
	}

	public boolean isFriendOf(Account acc, Account target) throws SQLException {
		return getFriend(acc, target.getId()) != null;
	}

	private T getFriend(Account acc, int target) throws SQLException {
		List<T> res = queryBuilder().where().eq(Friend.ACCOUNT_ID, acc.getId()).and()
				.eq(Friend.TARGET_ID, target).query();

		assert (res.size() <= 1);

		return res.size() == 1 ? res.get(0) : null;
	}

	public List<T> getFriends(Account acc) throws SQLException {
		return queryBuilder().where().eq(Friend.ACCOUNT_ID, acc.getId()).query();
	}

	@SuppressWarnings("unchecked")
	public void deleteFriends(Account acc, List<Account> friends) throws SQLException {
		List<Integer> ids = new ArrayList<Integer>(friends.size());
		for (Account friend : friends)
			ids.add(friend.getId());
		delete((PreparedDelete<T>) deleteBuilder().where().eq(Friend.ACCOUNT_ID, acc.getId()).and()
				.in(Friend.TARGET_ID, ids).prepare());
	}

	public List<Account> findFriends(Account acc, ID id, String userLike, String emailLike)
			throws SQLException {
		if (id != null) {
			Friend friend = (Friend) getFriend(acc, (Integer) id);

			if (friend != null) {
				DaoFactory.getInstance().createDao(Account.class).refresh(friend.getTarget());
				return Collections.singletonList(friend.getTarget());
			}
		}
		userLike = userLike.replace("'", "\'");
		emailLike = userLike.replace("'", "\'");
		
		userLike = userLike.replace("%", "\\%");
		String nameLike = userLike + "%";
		userLike = "%" + userLike + "%";

		if (emailLike != null) {
			emailLike = emailLike.replace("%", "\\%");
			emailLike = "%" + emailLike + "%";
		}
		
		GenericRawResults<Object[]> res;
		if (emailLike != null)
			res = queryRaw(
					"SELECT acc.* FROM Friend fri "
							+ "JOIN Account acc "
							+ "ON fri.target_id = acc.id "
							+ "WHERE fri.account_id = ? AND (acc.username LIKE ? OR acc.email LIKE ? OR acc.firstName LIKE ? OR acc.lastName LIKE ?)",
					new DataType[] { DataType.INTEGER, DataType.STRING, DataType.STRING,
							DataType.STRING, DataType.STRING, DataType.STRING, DataType.STRING },
					Integer.toString(acc.getId()), userLike, emailLike, nameLike, nameLike);
		else
			res = queryRaw("SELECT acc.* FROM Friend fri " + "JOIN Account acc "
					+ "ON fri.target_id = acc.id "
					+ "WHERE fri.account_id = ? AND acc.username = ?", new DataType[] {
					DataType.STRING, DataType.STRING, DataType.STRING, DataType.STRING },
					Integer.toString(acc.getId()), userLike);

		List<Account> accounts = new LinkedList<Account>();
		for (Object[] row : res) {
			Account resAcc = new Account((String) row[1], (String) row[2], (String) row[3],
					(String) row[4], (String) row[5], false);
			resAcc.setId((Integer) row[0]);
			accounts.add(resAcc);
		}
		return accounts;
	}
}
